import sys
import json
import time
import redis
import signal
import socket
import uuid


class RedisClient:
    def __init__(self, mq_url, stream_channel, worker):
        # 获取worker的类名
        self.worker_type = worker.__class__.__name__ if worker else ''

        # 对应redis的属性
        self.redis = redis.Redis.from_url(mq_url)
        self.stream_channel = stream_channel
        self.result_channel = 'task_result'
        self.heartbeat_channel = 'heartbeat'  # 心跳频道
        self.shutdown_channel = 'shutdown'   # 关闭频道
        self.worker = worker
        self.group_name = 'worker_group'
        self.consumer_name = self.generate_short_uuid()
        self.running = False

        # 创建消费者组
        try:
            self.redis.xgroup_create(
                self.stream_channel, self.group_name, id='0', mkstream=True)
        except redis.exceptions.ResponseError as e:
            if "BUSYGROUP" not in str(e):
                raise

        # 设置信号处理
        # signal.signal(signal.SIGINT, self.signal_handler)
        # signal.signal(signal.SIGTERM, self.signal_handler)

        # 发送心跳信息
        self.heartbeat_interval = 5
        self.custom_info = {}

        self.ip = self.get_local_ip()
        print(f'本地ip地址: {self.ip}')

    def get_local_ip(self):
        """获取当前机器的 IP 地址"""
        try:
            # 创建一个 UDP 套接字
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(("8.8.8.8", 80))  # 连接到公共 DNS 服务器
            ip = s.getsockname()[0]  # 获取本地 IP 地址
            s.close()
            return ip
        except Exception as e:
            print(f"获取 IP 地址失败: {e}")
            return "Unknown IP"

    def setCustomInfo(self, custom_info):
        self.custom_info = custom_info

    def generate_short_uuid(self):
        # 生成一个标准的 UUID
        full_uuid = uuid.uuid4().hex
        # 截取前 8 个字符
        short_uuid = full_uuid[:8]
        return short_uuid

    def signal_handler(self, signum, frame):
        print("接收到关闭信号，准备退出...")
        self.running = False
        self.cleanup()
        sys.exit(0)

    def start(self):
        try:
            self.running = True
            pubsub = self.redis.pubsub()
            pubsub.subscribe(self.shutdown_channel)  # 订阅关闭频道

            last_heartbeat_time = time.time()

            while self.running:
                # 发送心跳消息
                if time.time() - last_heartbeat_time > self.heartbeat_interval:
                    self.redis.publish(self.heartbeat_channel, json.dumps({
                        'workerId': self.consumer_name,
                        'content': {
                            "ip": self.ip,
                            "customInfo": self.custom_info
                        }
                    }))
                    last_heartbeat_time = time.time()

                # 检查是否接收到关闭信号
                message = pubsub.get_message()
                if message and message['type'] == 'message' and message['channel'] == self.shutdown_channel:
                    print("接收到关闭信号，准备退出...")
                    self.running = False
                    break

                # 从消费者组中读取消息
                messages = self.redis.xreadgroup(
                    self.group_name, self.consumer_name, {self.stream_channel: '>'}, count=1, block=1000
                )
                if messages:
                    for _, stream_messages in messages:
                        for message_id, message_fields in stream_messages:
                            message = json.loads(message_fields[b'message'])

                            # 处理消息
                            if self.worker:
                                result = self.worker.process(message)

                            # 将结果发布到 worker-result 频道
                            self.redis.publish(
                                self.result_channel, json.dumps(result))
                            print(f"结果已发布到频道task_result: {result}")

                            # 确认消息已被处理
                            self.redis.xack(self.stream_channel,
                                            self.group_name, message_id)

        except KeyboardInterrupt:
            print("接收到中断信号，准备退出...")
        except Exception as e:
            print(f"Redis 错误: {e}")
        finally:
            self.cleanup()

    def cleanup(self):
        """清理 Redis 连接"""
        if self.redis:
            self.redis.close()
            print("Redis 连接已关闭")
